package com.kotlin.notes.deadlock

import java.util.*
import java.util.concurrent.locks.ReentrantLock

fun main() {
    usingReentrantLock()
    usingSynchronized()
}

fun usingSynchronized() {
    val accountA = Account(10000, "A")
    val accountB = Account(10000, "B")

    val t1 = Thread {
        val rand = Random()
        for (i in 0..10) {

            synchronized(accountA) {
                println("t1 aquired deadlock on $accountA")
                synchronized(accountB) {
                    println("t1 aquired deadlock on $accountB")
                    Account.transfer(accountA, accountB, rand.nextInt(1000))
                }
            }

        }
    }

    val t2 = Thread {
        val rand = Random()
        for (i in 0..10) {

            synchronized(accountB) {
                println("t2 aquired deadlock on $accountB")
                synchronized(accountA) {
                    println("t2 aquired deadlock on $accountA")
                    Account.transfer(accountB, accountA, rand.nextInt(1000))
                }
            }

        }

    }

    t1.start()
    t2.start()
}

fun usingReentrantLock() {
    val accountA = Account(10000, "A")
    val accountB = Account(10000, "B")

    val lock1 = ReentrantLock()
    val lock2 = ReentrantLock()

    val t1 = Thread {
        val rand = Random()
        for (i in 0..10) {

            lock1.lock()
            lock2.lock()
            try {
                Account.transfer(accountA, accountB, rand.nextInt(1000))
            } finally {
                lock1.unlock()
                lock2.unlock()
            }
        }
    }

    val t2 = Thread {
        val rand = Random()
        for (i in 0..10) {
            lock2.lock()
            lock1.lock()
            try {
                Account.transfer(accountB, accountA, rand.nextInt(1000))
            } finally {
                lock2.unlock()
                lock1.unlock()
            }
        }
    }

    t1.start()
    t2.start()
}


